#ifndef __SOCKETS_H
#define __SOCKETS_H
#include <stdio.h>
#include <stdint.h>
#include "arpa/inet.h"

#ifdef __cplusplus
extern "C" {
#endif

/* If your port already typedef's sa_family_t, define SA_FAMILY_T_DEFINED
   to prevent this code from redefining it. */
#if !defined(sa_family_t) && !defined(SA_FAMILY_T_DEFINED)
typedef uint8_t sa_family_t;
#endif

#if !defined(in_port_t) && !defined(IN_PORT_T_DEFINED)
typedef uint16_t in_port_t;
#endif

struct sockaddr_in {
    uint8_t         sin_len;
    sa_family_t     sin_family;
    in_port_t       sin_port;
    struct in_addr  sin_addr;
#define SIN_ZERO_LEN 8
    char            sin_zero[SIN_ZERO_LEN];
};

struct sockaddr_in6 {
    uint8_t            sin6_len;      /* length of this structure    */
    sa_family_t     sin6_family;   /* AF_INET6                    */
    in_port_t       sin6_port;     /* Transport layer port #      */
    uint32_t           sin6_flowinfo; /* IPv6 flow information       */
    struct in6_addr sin6_addr;     /* IPv6 address                */
    uint32_t           sin6_scope_id; /* Set of interfaces for scope */
};

struct sockaddr {
    uint8_t     sa_len;
    sa_family_t sa_family;   /* socket 地址协议族 */
    char        sa_data[14]; /* socket 地址数据 */
};

struct sockaddr_storage {
    uint8_t     s2_len;
    sa_family_t ss_family;
    char        s2_data1[2];
    uint32_t    s2_data2[3];
#if WED_IPV6
    uint32_t    s2_data3[3];
#endif /* WED_IPV6 */
};

#if !defined(socklen_t) && !defined(SOCKLEN_T_DEFINED)
typedef uint32_t socklen_t;
#endif

/*
 * Options and types related to multicast membership
 */
#define IP_ADD_MEMBERSHIP  3
#define IP_DROP_MEMBERSHIP 4

typedef struct ip_mreq {
    struct in_addr imr_multiaddr; /* IP multicast address of group */
    struct in_addr imr_interface; /* local IP address of interface */
} ip_mreq;

#define SOCK_STREAM     1    /* 基于 TCP 协议*/
#define SOCK_DGRAM      2    /* 基于 UDP 协议（data grams）*/
#define SOCK_RAW        3    /* 原始套接字*/
/*
 * Options and types for UDP multicast traffic handling
 */
#define IP_MULTICAST_TTL   5
#define IP_MULTICAST_IF    6
#define IP_MULTICAST_LOOP  7


/*
 * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c)
 */
#define SO_REUSEADDR   0x0004 /* Allow local address reuse */
#define SO_KEEPALIVE   0x0008 /* keep connections alive */
#define SO_BROADCAST   0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */

#define SO_REUSEPORT    0x0200 /* Unimplemented: allow local address & port reuse */
#define SO_ERROR        0x1007 /* get error status and clear */

/*
 * Level number for (get/set)sockopt() to apply to socket itself.
 */
#define  SOL_SOCKET  0xfff    /* options for socket level */

#define AF_UNSPEC       0               /* 无特定网络协议*/
#define AF_INET         2               /* IPv4 网络协议*/
#define AF_INET6        10              /* IPv6 网络协议*/
#define AF_PACKET 17
#define PF_PACKET AF_PACKET  /* 通常与 AF_PACKET 同值 */

#define IPPROTO_IP      0
#define IPPROTO_ICMP    1
#define IPPROTO_TCP     6
#define IPPROTO_UDP     17

/*
 * Options for level IPPROTO_TCP
 */
#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */
#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */
#define TCP_KEEPIDLE   0x03    /* set pcb->keep_idle  - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */
#define TCP_KEEPINTVL  0x04    /* set pcb->keep_intvl - Use seconds for get/setsockopt */
#define TCP_KEEPCNT    0x05    /* set pcb->keep_cnt   - Use number of probes sent for get/setsockopt */

#define SHUT_RD   0
#define SHUT_WR   1
#define SHUT_RDWR 2

#define POLLIN     0x1
#define POLLOUT    0x2
#define POLLERR    0x4
#define POLLNVAL   0x8
typedef unsigned int nfds_t;
struct pollfd
{
  int fd;
  short events;
  short revents;
};

#define FIONREAD 0x541B

int getsockopt(int        sockfd,
               int        level,
               int        optname,
               void      *optval,
               socklen_t *optlen);

int setsockopt(int         sockfd,
               int         level,
               int         optname,
               const void *optval,
               socklen_t   optlen);
int accept(int s, struct sockaddr *addr, socklen_t *addrlen);

int recv(int s, void *mem, size_t len, int flags);
int recvfrom(int s, void *mem, size_t len, int flags,
              struct sockaddr *from, socklen_t *fromlen);
int send(int s, const void *data, size_t size, int flags);
int sendto(int s, const void *data, size_t size, int flags,
            const struct sockaddr *to, socklen_t tolen);
#define ntohs(x) htons(x)

uint16_t htons(uint16_t n);
uint32_t htonl(uint32_t n);

const char *gai_strerror(int errcode);
int socket(int domain, int type, int protocol);
int bind(int s, const struct sockaddr *name, socklen_t namelen);
int getsockname(int s, struct sockaddr *name, socklen_t *namelen);
int gethostname(char *name, size_t len);
int listen(int s, int backlog);
int ioctl(int s, long cmd, void *argp);
int shutdown(int s, int how);
int poll(struct pollfd *fds, nfds_t nfds, int timeout);
const char * inet_ntop(int af, const void *src, char *dst, socklen_t size);
int connect(int s, const struct sockaddr *name, socklen_t namelen);
int select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,
            struct timeval *timeout);
int pipe(int pipefd[2]);
int access(const char *pathname, int mode);

#endif
